import time

from NSGA2 import *
from crossover import *
from init import read
from mutation import *
from selection import *
from mpl_toolkits.mplot3d import Axes3D

# fileName = f"data/n01_2.mm"
fileName = f"data/example"
pop_size = 30  # 种群规模
pop = []
chosen3d = True  # 3d散点图
resourceNum = 0  # 资源种类数
modeNum = 0  # 模式种类数
pc = 0.9  # 交叉概率
pm = 0.1  # 变异概率
maxGen = 50  # 最大进化代数
maxResources = []  # 最大资源限量
step = []  # 资源增加步长
upBoardStep = 8
increased = []  # 资源增加量
stepCost = []  # 单位时间增加单位资源的成本
result = set()  # 结果集
cost = []
increasedCost = []


def init():
    """读取算例"""
    global result
    actNum, actList, resourceNum, resources, modeNum = read(fileName)
    initResources = resources.copy()  # 资源备份
    """一部分论文和算例中未出现的变量，随机代替,包括资源增加步长与单位时间增加单位资源的成本"""
    """计算上界"""
    maxResources = CPMBasedHeuristic(actList, resources, modeNum)
    # maxResources = [8]

    print("maxResources:", maxResources)
    print("resourceNum:", resourceNum)
    print("init_resources:", resources)
    """计算步长与循环终止条件"""
    np.random.seed(12)
    for i in range(0, resourceNum):
        tmp_step = np.ceil((maxResources[i] - initResources[i]) / upBoardStep)
        step.append(int(tmp_step))
        print("step:", step)
        stepCost.append(8)
        # stepCost.append(np.random.randint(1, 50))
    """柔性资源可用量"""
    for i in range(0, upBoardStep):
        increased.clear()
        increasedCost.clear()
        for k in range(0, resourceNum):
            increased.append(step[k] * i)
            increasedCost.append(increased[k] * stepCost[k])  # 未乘项目工期
        for j in range(0, resourceNum):
            resources[j] = int(increased[j]) + initResources[j]
        """生成初始种群"""
        global pop
        pop += encode(modeNum, int(pop_size / upBoardStep), actNum, actList, resourceNum, resources, increasedCost)
    print("pop_size：", len(pop))
    """进入遗传算法循环"""
    gen = 0
    """创建画布"""
    # plt.figure(i, dpi=150, figsize=(10, 16))  # 画布分辨率及大小
    plt.figure()
    plt.title("gen-res")  # 标题
    if chosen3d:
        ax = plt.subplot(projection="3d")
    while gen < maxGen:
        """当前代次"""
        gen = gen + 1
        """保留亲代种群"""
        ancestor = copy.deepcopy(pop)
        for indiv in ancestor:
            indiv.fit(actList, indiv.resources, indiv.increasedCost)
        for indiv in pop:
            indiv.fit(actList, indiv.resources, indiv.increasedCost)
        """交叉"""
        pop = crossover(pop, pc, actList, resources)
        """变异"""
        pop = mutation(pop, pm, actList, resources)
        """计算子代目标函数"""
        for indiv in pop:
            indiv.fit(actList, indiv.resources, indiv.increasedCost)
        """合并亲子两代并就行非支配排序"""
        tmp = pop + ancestor
        # print(len(pop))
        """快速非支配排序"""
        tmp, paretoRate, paretoNum = NSGA2(tmp)
        """当前代帕累托结果集"""
        print("--------------------------------------------------")
        print("-------------当前代帕累托结果:{}----------------------------".format(gen))
        print("--------------------------------------------------")
        for k in range(0, len(pop)):
            print(pop[k], end="")
            if k < paretoNum:
                print("pareto", end="\n\n")
            else:
                print()
        """选择"""
        pop = binary_championship_selection(tmp)
        """当前代的结果绘图"""
        x = [gen] * len(pop)
        y1 = [a.duration for a in pop]
        y2 = [a.cost for a in pop]
        if chosen3d:
            # 三维图形
            ax.set_xlabel("gen")
            ax.set_ylabel("duration")
            ax.set_zlabel("cost")
            for i in range(0, len(x)):
                if i < paretoNum:
                    ax.scatter(x, y1, y2, c='r')
                else:
                    ax.scatter(x, y1, y2, c='g')

        else:
            # 工期散点
            plt.subplot(3, 1, 1)
            plt.xlabel("gen")
            plt.ylabel("duration")
            plt.scatter([gen] * len(y1), y1)
            # 成本散点
            plt.subplot(3, 1, 2)
            plt.xlabel("gen")
            plt.ylabel("cost")
            plt.scatter([gen] * len(y2), y2)
            # 亲子合并中间种群帕累托非支配比例
            plt.subplot(3, 1, 3)
            plt.xlabel("gen")
            plt.ylabel("paretoRate")
            plt.scatter(gen, paretoRate, marker='*')
            plt.grid(True, alpha=0.5, axis='both', linestyle=':')  # 添加网格线
        """每个gen生成一个结果图"""

        # print("generation： ", gen)
        # print("pop_size: ", len(pop))
        # print(pop)
        # for indiv in set(pop):
        #     print(indiv)
        # """当种群中解个数唯一时，退出遗传"""
        # if len(set(pop)) == 1:
        #     break
        # """当帕累托最优充满种群时，停止遗传迭代"""
        # if paretoRate == 1:
        #     break
    """保存散点图"""
    print(resources)
    plt.savefig("analysis/{}resources.png".format("3d-" if chosen3d else "2d-"))
    """将当前资源可用量下的结果去重后存入解集"""
    tmp_res = set(pop)  # 按属性去重，实现ep和hash方法
    result = result | tmp_res

    print("***********全部柔性资源的最终解集***************")
    print("***********全部柔性资源的最终解集***************")
    print("***********全部柔性资源的最终解集***************")

    """对最终解集进行排序"""
    result = list(result)
    result, res_paretoRate, res_paretoNum = NSGA2(result)
    # result.sort(key=lambda x: x.duration)  # 按工期排序
    # print(result)
    """成本优化"""
    result = costImprove(result, paretoRate)
    """最终结果"""
    for indiv in result:
        print(indiv)
    plt.figure()
    x = [a.duration for a in result]
    y = [a.cost for a in result]
    plt.title("result")
    plt.xlabel("duration")
    plt.ylabel("cost")
    plt.scatter(x, y)
    plt.savefig("analysis/result")


if __name__ == '__main__':
    """控制台内容输出到文件"""
    filename = "analysis/log.txt"
    standard_output = sys.stdout
    sys.stdout = open(filename, "w+")
    """计算程序运行时间"""
    start = time.time()
    init()
    end = time.time()
    print("程序运行时间：", end - start)
    """输出控制台日志"""
    sys.stdout = standard_output
    print(open(filename, "r+").read())
    """显示绘图"""
    plt.show()
